#置换选择1
Replacement_1=[57, 49, 41, 33, 25, 17, 9,
        1, 58, 50, 42, 34, 26, 18,
        10, 2, 59, 51, 43, 35, 27,
        19, 11, 3, 60, 52, 44, 36,
        63, 55, 47, 39, 31, 23, 15,
        7, 62, 54, 46, 38, 30, 22,
        14, 6, 61, 53, 45, 37, 29,
        21, 13, 5, 28, 20, 12, 4]
#置换选择2
Replacement_2=[14, 17, 11, 24, 1, 5,
        3, 28, 15, 6, 21, 10,
        23, 19, 12, 4, 26, 8,
        16, 7, 27, 20, 13, 2,
        41, 52, 31, 37, 47, 55,
        30, 40, 51, 45, 33, 48,
        44, 49, 39, 56, 34, 53,
        46, 42, 50, 36, 29, 32]

# 构建8个S-盒模型
S1 = [[14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7],
      [0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8],
      [4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0],
      [15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13]]

S2 = [[15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10],
      [3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5],
      [0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15],
      [13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9]]

S3 = [[10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8],
      [13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1],
      [13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7],
      [1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12]]

S4 = [[7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15],
      [13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9],
      [10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4],
      [3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14]]

S5 = [[2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9],
      [14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6],
      [4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14],
      [11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3]]

S6 = [[12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11],
      [10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8],
      [9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6],
      [4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13]]

S7 = [[4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1],
      [13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6],
      [1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2],
      [6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12]]

S8 = [[13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7],
      [1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2],
      [7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8],
      [2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11]]
S_BOX = [S1, S2, S3, S4, S5, S6, S7, S8]
def char2bin(char):
    '''
    将单个字符转为8位二进制
    :param char:
    :return:string型
    '''
    binary=bin(ord(char)).replace('0b','')
    return (8-len(binary))*'0'+binary

def string2bin(string):
    '''
    将8个字符的字符串转换成64位二进制列表
    :param char:
    :return:int型
    '''
    if len(string)!=8:
        raise IOError('the string \'{}\'is not 64 bit!'.format(string))
    tmp=[]
    for char in string:
        tmp.append(char2bin(char))
    return [int(number) for number in ''.join(tmp)]

def bin2string(text):
    if len(text) !=64:
        raise IOError('Error!')
    text = [str(number) for number in text]
    result = []
    for i in range(8):
        BinString =''.join(text[i*8:i*8+8])
        result.append(chr(int(BinString,2)))
    return ''.join(result)

def num2bin(num,length):
    '''
    将十进制数转为length位二进制字符串
    :param num:
    :return:
    '''
    tmp = bin(num).replace('0b','')
    return (length-len(tmp))*'0'+tmp

def shift(text,times):
    '''
    移位
    :param text: 要移位的内容
    :param times: 移位次数
    :return:
    '''
    return text[times:] + text[:times]

def CreateSubKeys(key):
    '''
    生成16个轮密钥

    :param key:
    :return:
    '''
    result = []
    key56 = [key[Replacement_1[i]-1] for i in range(56)]
    #每轮的移位表
    SHIFT_TABLE = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]


    #16轮子密钥生成
    for i in range(16):
        #每28位为一部分，进行循环左移
        key28left = shift(key[:28],SHIFT_TABLE[i])
        key28right = shift(key[28:],SHIFT_TABLE[i])

        key56 = key28left+key28right
        #对56位密钥进行置换选择2，压缩为48位
        key48 = [key56[Replacement_2[i]-1] for i in range(48)]

        result.append(key48)
    return result


def IPReplacement(text):
    '''
    IP置换
    :param text:
    :return:
    '''
    IP = [58, 50, 42, 34, 26, 18, 10, 2,
          60, 52, 44, 36, 28, 20, 12, 4,
          62, 54, 46, 38, 30, 22, 14, 6,
          64, 56, 48, 40, 32, 24, 16, 8,
          57, 49, 41, 33, 25, 17, 9, 1,
          59, 51, 43, 35, 27, 19, 11, 3,
          61, 53, 45, 37, 29, 21, 13, 5,
          63, 55, 47, 39, 31, 23, 15, 7]
    return [text[IP[i] - 1] for i in range(64)]

def IPReverseReplacement(text):
    '''
    IP逆置换
    :param text:
    :return:
    '''
    IP_Reverse=[40, 8, 48, 16, 56, 24, 64, 32,
                  39, 7, 47, 15, 55, 23, 63, 31,
                  38, 6, 46, 14, 54, 22, 62, 30,
                  37, 5, 45, 13, 53, 21, 61, 29,
                  36, 4, 44, 12, 52, 20, 60, 28,
                  35, 3, 43, 11, 51, 19, 59, 27,
                  34, 2, 42, 10, 50, 18, 58, 26,
                  33, 1, 41, 9, 49, 17, 57, 25]
    return [text [IP_Reverse[i]-1] for i in range(64)]

def ExtendRepalcement(text):
    '''
    扩展置换E：将32位输入按规则拓展为48位结果
    :param text:
    :return:
    '''
    Extend=[32, 1, 2, 3, 4, 5,
         4, 5, 6, 7, 8, 9,
         8, 9, 10, 11, 12, 13,
         12, 13, 14, 15, 16, 17,
         16, 17, 18, 19, 20, 21,
         20, 21, 22, 23, 24, 25,
         24, 25, 26, 27, 28, 29,
         28, 29, 30, 31, 32, 1 ]
    return [text[Extend[i]-1]for i in range(48)]

def S_BoxReplacement(text):
    '''
    S盒置换，将48位分为8个组，每个组进入S盒得到4位输出
    :param text:
    :return: 返回合并以后的32位的结果
    '''
    result = []
    for i in range(0,8):
        #分组
        tmp = text[i*6:i*6+6]
        #根据第一位和第6位形成行
        row = int(str(tmp[0]) + str(tmp[-1]), 2)
        #其余四位构列
        column = int(str(tmp[1]) + str(tmp[2]) + str(tmp[3]) + str(tmp[4]), 2)
        #取出该十进制数
        letter = S_BOX[i][row][column]
        #转换为二进制数
        result.append(num2bin(letter,4))
    return [int(x) for x in ''.join(result)]

def PBoxReplacement(text):
    '''
    P盒置换：将32位输入按P规则置换后返回32位结果
    :param text:
    :return:
    '''
    P = [16, 7, 20, 21, 29, 12, 28, 17,
         1, 15, 23, 26, 5, 18, 31, 10,
         2, 8, 24, 14, 32, 27, 3, 9,
         19, 13, 30, 6, 22, 11, 4, 25]
    return [text[P[i]-1] for i in range(32)]

def XOR(a,b):
    '''
    对a,b进行按位异或操作，将结果返回
    :param a:
    :param b:
    :return:
    '''
    return [i^j for i,j in zip(a,b)]

